package com.qf.service.impl;

import com.qf.config.RabbitMqConfig;
import com.qf.config.RedisKey;
import com.qf.dao.UseRepository;
import com.qf.pojo.reqVo.UserReq;
import com.qf.pojo.respVo.BaseResp;
import com.qf.pojo.vo.entity.User;
import com.qf.service.UserService;
import com.qf.utils.JWTUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    UseRepository useRepository;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    RedissonClient redissonClient;


    @Override
    public BaseResp findAll() {
        List<User> all = useRepository.findAll();
        System.out.println("all = " + all);
        return new BaseResp().Ok("success",all,null);
    }

    @Override
    public BaseResp saveOrUpdate(UserReq userReq) {
        User user = new User();
        BeanUtils.copyProperties(userReq,user);
        useRepository.saveAndFlush(user);
        return new BaseResp().Ok("success",null,null);
    }

    @Override
    public BaseResp del(Integer userid) {
        useRepository.deleteById(userid);
        return new BaseResp().Ok("删除成功",null,null);
    }

    @Override
    public BaseResp findUserByToken(HttpServletRequest request) {
        String token = request.getHeader("token");
        Object o = redisTemplate.opsForValue().get(RedisKey.LOGIN_KEY + token);
        //使用jwt进行解析
        Map map = JWTUtils.verfiyToken(o.toString());
        if (map!=null){
            //从map集合中获取到登录的用户id
            Integer userid= Integer.parseInt(map.get("id").toString());
            Optional<User> byId = useRepository.findById(userid);
            return new BaseResp().Ok("success",byId.get(),null);
        }
        return new BaseResp().Fail(0,"解析失败,可能用户未登录!");
    }

    @Override
    public BaseResp getEmail(String email) {
        //获取email对象
        User byEmail = useRepository.findByEmail(email);
        if (byEmail==null){
            return new BaseResp().Ok("邮箱可用",null,null);
        }
        return new BaseResp().Fail(0,"邮箱已经被占用,请重试");
    }

    @Override
    public BaseResp userName(UserReq userReq) {
        //获取用户名对象
        User byLoginName = useRepository.findByLoginName(userReq.getUserName());
        if (byLoginName==null){
            return new BaseResp().Ok("用户名可以用",null,null);
        }
        return new BaseResp().Ok("用户名已重复！",null,null);
    }


    /*
    需要注意，如果多个用户同时进行注册，使用的同一个邮箱
    那么就会出现给改邮箱多次发送邮件的情况，需要加入锁保证当前只有一个线程进入
     */
    @Override
    public BaseResp getCode(String email) {
        //设置一个邮箱在有限的时间内只允许发三次邮箱,使得redis的原子性+1
        //1判断邮箱是否重复?
        User byEmail = useRepository.findByEmail(email);
        //2.验证redis中是否已经给邮箱发送过验证码
        Boolean aBoolean = redisTemplate.hasKey(RedisKey.VALIDATA_KEY + email);
        if (aBoolean){
            return new BaseResp().Fail(0,"邮箱已经发送,请5分钟后进行重试");
        }
        RLock lock = redissonClient.getLock("lock");
        boolean b=false;
        try {
            b=lock.tryLock(30, TimeUnit.SECONDS);
            if (b){
                if (byEmail!=null){
                return new BaseResp().Fail(0,"邮箱已重复");
                }
                //2.发送邮件 使用异步的方式进行邮件的发送 +rabbitmq来进行邮件的发送
                rabbitTemplate.convertAndSend("","damai-email-queue",email);
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            //判断当前是否是枷锁状态,如果是则进行释放锁
        boolean locked=lock.isLocked();
            lock.unlock();
        }
        return new BaseResp().Ok("正在发送中,请稍后",null,null);
    }


    //将注册放置在锁中保证线程的唯一

    @Override
    public BaseResp registry(UserReq userReq) {
        RLock lock = redissonClient.getLock("zhuce-lock");
        boolean b=false;

        try {
            b=lock.tryLock(30,TimeUnit.SECONDS);

            if (b){
            //判断redis中是否有该用户的验证码
                Boolean aBoolean = redisTemplate.hasKey(RedisKey.VALIDATA_KEY + userReq.getEmail());
                if (!aBoolean){
                    return new BaseResp().Fail(0,"验证码已过期,或未发送!");
                }
                //如果有的话,将前端获取到的验证码跟redis的进行比对
                Object o = redisTemplate.opsForValue().get(RedisKey.VALIDATA_KEY + userReq.getEmail());
                if (!o.toString().equals(userReq.getCode())){
                    //如果reids的跟前端传过来的验证码不一致表示错误.
                    return new BaseResp().Fail(0,"验证码比对错误!!!!");
                }
                //判断邮箱是否可用
                User byEmail = useRepository.findByEmail(userReq.getEmail());
                if (byEmail!=null){
                    return new BaseResp().Fail(0,"邮箱被占用");
                }
                User byLoginName = useRepository.findByLoginName(userReq.getUserName());
                if (byLoginName!=null){
                    return new BaseResp().Fail(0,"用户名已经被占用!");
                }
                //以上都通过的情况才可以存入mysql数据库中
                User user = new User();
                BeanUtils.copyProperties(userReq,user);
                user.setCreatTime(new Date());
                //设置用户的状态，用户操作非法，可以再后台管理将用户的状态修改位0，代表当前用户被禁用
                user.setStatus(1);
                useRepository.saveAndFlush(user);
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
        boolean locking=lock.isLocked();
        lock.unlock();
        }
        return new BaseResp().Ok("注册成功",null,null);
    }




    @Override
    public BaseResp login(UserReq userReq) {
        User byLoginName = useRepository.findByLoginName(userReq.getUserName());
        if (byLoginName==null){
            return new BaseResp().Fail(0,"请先注册！");
        }
        //设置如果用户三次输入错误则禁止用户1分钟内继续登录
        Boolean aBoolean = redisTemplate.hasKey(userReq.getUserName());
        if (aBoolean){
            Object o = redisTemplate.opsForValue().get(userReq.getUserName());
            if (Integer.parseInt(o.toString())>3){
                redisTemplate.expire(userReq.getUserName(),120,TimeUnit.SECONDS);
                return new BaseResp().Fail(0,"用户密码错误大于三次,禁止2分钟内登录!");
            }
        }
        if (!userReq.getPassword().equals(byLoginName.getPassword())){
            //将该用户输入错误的次数+1
                redisTemplate.opsForValue().increment(userReq.getUserName());
            return new BaseResp().Fail(0,"密码错误!");
        }
        //登录成功后，通过jwt生成token串
        Map map=new HashMap();
        map.put("userName",byLoginName.getUserName());
        map.put("userId",byLoginName.getUserId());
        String jwt = JWTUtils.signToken(map);
        //生成token后需要将该token放置在redis中，进行用户的认证。以及进行长时间未登录自动注销功能
        String token= UUID.randomUUID().toString();
        redisTemplate.boundValueOps(RedisKey.LOGIN_KEY+token)
                .set(jwt,300,TimeUnit.SECONDS);
        //认证通过,用户拥有三十分种的未登录自动注销功能
        return new BaseResp().Ok("登录成功",token,null);
    }
}
